package com.my.security.config;

import com.my.security.component.AppReactiveUserDetailService;
import jakarta.annotation.Resource;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;

/**
 * @author zhupanlin
 * @version 1.0
 * @description: TODO
 * @date 2024/2/21 19:55
 */
@Configuration
public class AppSecurityConfiguration {
    
    @Resource
    AppReactiveUserDetailService appReactiveUserDetailService;
    
    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http){
        // 1.定义哪些请求需要认证，哪些不需要
        http.authorizeExchange(exchange -> {
            // 1.1.允许所有人都访问静态资源
            exchange.matchers(PathRequest.toStaticResources()
                    .atCommonLocations()).permitAll();
            
            // 1.2.剩下的所有请求都需要认证（登录）
            exchange.anyExchange().authenticated();
        });

        // 开启默认的表单登录
        http.formLogin();
        
        // 3.安全控制
        http.csrf(csrfSpec -> {
            csrfSpec.disable();
        });
        
        // 目前认证：用户名是user，密码是默认生成
        
        // 4.配置认证规则：如何去数据库中查询到用户; 
        // Spring Security 底层使用 ReactiveAuthenticationManager 去查询用户信息
        // 我们只需要自己写一个 ReactiveUserDetailService：响应式的用户详情查询服务
        http.authenticationManager(
                new UserDetailsRepositoryReactiveAuthenticationManager(
                        appReactiveUserDetailService));
        
        // 构建出安全配置
        return http.build();
    }
    
    @Primary
    @Bean
    PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return encoder;
    }
    
}
